package com.lagou.lesson2.factory;

import com.lagou.lesson2.core.annotation.Autowired;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Ceven
 * 工厂类，生产对象（使用反射技术）
 */
public class BeanFactory {

    private static BeanFactory instance = new BeanFactory();
    private BeanFactory() {

    }
    public static BeanFactory getInstance() {
        return instance;
    }

    /**
     * key: 名称
     * value：bean的class
     */
    public static Map<String,Class<?>> beanDefinitionMap = new HashMap<>();  // 存储Bean的定义
    private static Map<String,Object> map = new HashMap<>();  // 存储对象

    private static Map<String,Object> earlyMap = new HashMap<>();  // 存储对象

    public <T> T createBean(String className, String beanId) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        Class<T> clazz = (Class<T>) Class.forName(className);
        //如果单例池中已经有成型的bean，直接返回
        if(map.get(beanId) != null) {
            return (T) map.get(beanId);
        }
        //创建，初始化bean
        T t = beanInit(clazz, beanId);
        System.out.println("before AOP t:" + t + "," + t.getClass().getName());
        //bean创建后，处理注解逻辑，创建代理对象
        t = (T) AnnotationAspectJAutoProxyCreator.getInstance().processAnnotationAspectProxy(t);
        System.out.println("after AOP t:" + t + "," + t.getClass().getName());
        //存储到map
        if(t != null) {
            map.put(beanId, t);
            map.put(clazz.getSimpleName(), t);
        }

        return t;
    }


    // 任务二：对外提供获取实例对象的接口（根据id获取）
    public Object getBean(String id) {
        return map.get(id);
    }

    public <T> T beanInit(Class<T> clazz, String beanId) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        System.out.println("beanInit: " + clazz);
        T bean = (T) clazz.newInstance();
        // 放到1级缓存中
        earlyMap.put(beanId, bean);
        Field[] declaredFields = clazz.getDeclaredFields();
        if(declaredFields != null) {
            for (Field declaredField : declaredFields) {
                Autowired annotation = declaredField.getAnnotation(Autowired.class);
                if(annotation != null) {
                    String defaultBeanName = declaredField.getName();
                    String refBeanName = getBeanName(annotation.value(), defaultBeanName);
                    System.out.println("refBeanName: " + refBeanName);
                    if(earlyMap.get(refBeanName) == null) {
                        //继续创建依赖对象
                        String refObjClass = beanDefinitionMap.get(refBeanName).getName();
                        Class refObjClazz = Class.forName(refObjClass);
                        System.out.println("依赖对象：" + refObjClass);
                        Object refObj =  createBean(refObjClass, refBeanName);
                        earlyMap.put(refBeanName, refObj);
                        declaredField.setAccessible(true);
                        declaredField.set(bean, refObj);
                    } else {
                        declaredField.setAccessible(true);
                        declaredField.set(bean, earlyMap.get(refBeanName));
                    }
                }
            }
        }
        return bean;
    }

    public String getBeanName(String annotatedName, String defaultName) {
        if(!"".equals(annotatedName.trim())) {
            return annotatedName;
        }
        return defaultName;
    }
}
